#pragma once
class VertexData;
class IndexData;
class VertexFactory;
class Mesh;
class Skeleton;
#include <vector>

typedef std::vector<WORD> IndexMap;

class SubMesh
{
public:
	SubMesh(const Mesh* parent);
	~SubMesh();

	const std::string& getName() const { return mName; }
	void setName(const std::string& v) { mName = v; }

	const std::string& getMaterialName() const { return mMaterialName; }
	void setMaterialName(const std::string& v) { mMaterialName = v; }

	bool getShareGeometry() const { return mShareGeometry; }
	void setShareGeometry(bool v) { mShareGeometry = v; }
	
	const IndexData* getIndexData() const { return mIndexData; }
	void setIndexData(IndexData* v) { mIndexData = v; }

	const Mesh* getParent() const { return mParent; }
	VertexFactory* getVertexFactory() const;
	const IndexMap& getBoneIndexMap() const { return mBoneIndexMap; }
	IndexMap& getBoneIndexMap() { return mBoneIndexMap; }

private:
	const Mesh* mParent;
	std::string mName;
	std::string mMaterialName;
	bool mShareGeometry;

	IndexData* mIndexData;

	VertexData* mVertexData;
	VertexFactory* mVertexFactory;
	IndexMap mBoneIndexMap;
};

class Mesh
{
public:
	friend class MeshManager;
	typedef std::vector<SubMesh*> SubMeshList;

public:
	const std::string& getName() const { return mName; }
	VertexFactory* getVertexFactory() const { return mVertexFactory; }
	const SubMeshList& getSubMeshes() const { return mSubMeshes; }
	const IndexMap& getBoneIndexMap() const { return mBoneIndexMap; }
	IndexMap& getBoneIndexMap() { return mBoneIndexMap; }

	const VertexData* getVertexData() const { return mVertexData; }
	void setVertexData(VertexData* v) { mVertexData = v; }

	const AxisAlignedBox& getBounds() const { return mAABB; }
	void setBounds(const AxisAlignedBox& v) { mAABB = v; }

	float getBoundRadius() const { return mBoundRadius; }
	void setBoundRadius(float v) { mBoundRadius = v; }

	const Skeleton* getSkeleton() const { return mSkeleton; }
	void setSkeleton(Skeleton* v) { mSkeleton = v; }

	void Init(bool gpuSkin = false);
	SubMesh* CreateSubMesh();

	SubMesh* GetSubMesh(size_t idx);
	const SubMesh* GetSubMesh(size_t idx) const;

private:
	Mesh(const std::string& name);
	virtual ~Mesh();

	const std::string mName;
	AxisAlignedBox mAABB;
	float mBoundRadius;

	VertexData* mVertexData;
	VertexFactory* mVertexFactory;
	IndexMap mBoneIndexMap;

	SubMeshList mSubMeshes;

	Skeleton* mSkeleton;
};

inline SubMesh* Mesh::GetSubMesh(size_t idx)
{
	if (idx < mSubMeshes.size())
		return mSubMeshes[idx];
	return NULL;
}

inline const SubMesh* Mesh::GetSubMesh(size_t idx) const
{
	if (idx < mSubMeshes.size())
		return mSubMeshes[idx];
	return NULL;
}